/**
 * 
 */
package it.polimi.leo.a3;

import it.polimi.leo.mw.IMiddleWare;
import it.polimi.leo.mw.IMiddleWareGroup;
import it.polimi.leo.mw.IMiddleWareNode;
import it.polimi.leo.mw.IMiddlewareMessage;
import it.polimi.leo.mw.JoinGroupException;
import it.polimi.leo.mw.IMiddleWare.IMiddlewareMessageFactory;
import it.polimi.leo.utils.TeaminatableThread;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Lev
 *
 */
public class A3Node extends TeaminatableThread {

    //String ID;
    IMiddleWare mw;
    IMiddlewareMessageFactory msgfactory;
    int capacity;
    /*
     * Internal state of each group:
     */
    Map<String, Object> states = new HashMap<String, Object>();
    //IDs of the group where I am superviser
    Set<String> supInGroups = new HashSet<String>();
    Map<String, IMiddleWareNode> myMwNodes = new HashMap<String, IMiddleWareNode>();

    public A3Node(String id, IMiddleWare mw, int capacity,
            IMiddleWareGroup... groups) throws JoinGroupException {

        this.mw = mw;
        this.msgfactory = mw.getIMiddlewareMessageFactory();
        for (IMiddleWareGroup g : groups) {
            this.myMwNodes.put(g.getID(), mw.createNode(g));
        }
        this.capacity = capacity;

    }

    public void sendMsgToFollowers(IMiddlewareMessage msg) {
        for (String id : supInGroups) {
            this.sendMsgToGroup(msg, id);
            //myMwNodes.get(id).sendMsg(msg);
        }
    }

    public void sendMsgToGroup(IMiddlewareMessage msg, String groupID) {
        myMwNodes.get(groupID).sendMsg(msg);
    }

    public void sendMsg(IMiddlewareMessage msg, String groupID,
            IMiddleWareNode node) {

        IMiddleWareNode n = myMwNodes.get(groupID);
        System.out.println("" + n);
        n.sendMsgTo(msg, node);

    }

    void decodeMsg(IMiddlewareMessage msg) throws JoinGroupException {
        switch (msg.getKind()) {
            case START_ELECTION:
                new ElectionManager(5000, mw, msg.getGroup());
                break;
            case BECOME_A_SUPERVISOR:
                supInGroups.add(msg.getGroup().getID());
                break;
            case BECOME_A_FOLLOWER:
                break;
            case UPDATE_STATE:
                sendMsgToFollowers(msg);
                states.put(msg.getGroup().getID(), msg.getPayLoad());
                break;
            case GIVE_FITNESS:
                myMwNodes.get(msg.getGroup().getID()).sendMsg(msgfactory.createDataMsg(this.capacity));
                break;
            case DO_TASK:
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                break;
            default:
                System.out.println("Undefined msg type");
                break;
        }
    }

    @Override
    public void run() {
        //IMiddlewareMessage msg;
        while (this.isNotTerminate()) {
            for (String key : this.myMwNodes.keySet()) {
                try {
                    IMiddleWareNode n = this.myMwNodes.get(key);
                    if (n.hasMsg()) {
                        decodeMsg(n.receiveMsg());
                    }
                } catch (JoinGroupException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

        }
    }

    @Override
    public void terminate() {
        for (IMiddleWareNode n : myMwNodes.values()) {
            try {
                n.leaveGroup();
            } catch (JoinGroupException ex) {
                Logger.getLogger(A3Node.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        super.terminate();
    }
}
